import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Scanner;

public class MultipleRemoteControlMain {

    private static final String IP_V4_ADDRESS_REGEX = "^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$";

    private static final String ADB_PATH = ".\\platform-tools\\adb.exe";
    private static final String SCRCPY_PATH = ".\\scrcpy\\scrcpy.exe";
//    private static final String ADB_PATH = "F:\\sdkNew\\platform-tools\\adb.exe";
//    private static final String SCRCPY_PATH = "D:\\scrcpy-win64-v1.23\\scrcpy.exe";

    private static String deviceSerial;

    private static final ArrayList<Process> processes = new ArrayList<>();

    public static void main(String[] args) {

        String os = System.getenv("OS");
        printMsg("当前操作系统：" + os);

        if (!os.toLowerCase().startsWith("windows")) {
            printMsg("请使用Windows系统运行本程序！");
            return;
        }
        Scanner scanner = new Scanner(System.in);
        Runtime runtime = Runtime.getRuntime();
        int result = listAndSelectDevices(runtime, scanner);
        switch (result) {
            case ConstantsCode.SUCCESS:
                break;
            case ConstantsCode.EXIT:
            case ConstantsCode.ERROR:
            case ConstantsCode.FAIL:
            default:
                exit();
                return;
        }
        doRemoteControl(runtime, scanner);
        exit();
    }

    /**
     * 开始执行远程控制
     *
     * @param runtime 程序运行环境
     * @param scanner 控制台输入
     */
    private static int doRemoteControl(Runtime runtime, Scanner scanner) {
        printMsg("请输入设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
        String deviceType;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
                continue;
            }
            if (!s.equals("1") && !s.equals("2") && !s.equals("3")) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    return ConstantsCode.EXIT;
                }
                printMsg("请输入正确的设备类型（1 福袋机，2 通用设备，3 自定义控制参数）(输入exit或quit退出程序)：");
                continue;
            }
            deviceType = s;
            break;
        }
        printMsg("正在发送远程控制命令，请耐心等待...");
        //设备显示内容旋转角度
        String deviceVideoOrientation;
        //窗口旋转角度
        String windowRotation;
        switch (deviceType) {
            case "1":
                deviceVideoOrientation = "270";
                windowRotation = "90";
                break;
            case "3":
                deviceVideoOrientation = getDeviceVideoOrientation(scanner);
                if (deviceVideoOrientation == null) {
                    return ConstantsCode.ERROR;
                }
                windowRotation = getWindowRotation(scanner);
                if (windowRotation == null) {
                    return ConstantsCode.ERROR;
                }
                break;
            case "2":
            default:
                deviceVideoOrientation = null;
                windowRotation = null;
                break;
        }
        try {

            StringBuilder cmdBuilder = new StringBuilder();
            cmdBuilder.append(SCRCPY_PATH + " -s ").append(deviceSerial);
            if (deviceVideoOrientation != null){
                cmdBuilder.append(" --angle=").append(deviceVideoOrientation);
            }
            if (windowRotation != null){
                cmdBuilder.append(" --capture-orientation=").append(windowRotation);
            }
            Process process = runtime.exec(cmdBuilder.toString());
            InputStream inputStream = process.getInputStream();
            startPrintThread(process, inputStream);
            process.waitFor();
            return ConstantsCode.SUCCESS;
        } catch (IOException | InterruptedException e) {
            return ConstantsCode.ERROR;
        }
    }

    /**
     * 获取窗口旋转角度
     *
     * @param scanner 控制台输入
     * @return 旋转角度
     */
    private static String getWindowRotation(Scanner scanner) {
        printMsg("请输入窗口旋转角度（只允许0 90 180 270）(输入exit或quit退出程序)：");
        String result;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入窗口旋转角度（只允许0 90 180 270）(输入exit或quit退出程序)：");
                continue;
            }
            if (!s.equals("0") && !s.equals("90") && !s.equals("180") && !s.equals("270")) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    result = null;
                    break;
                }
                printMsg("请输入正确的窗口旋转角度（只允许0 90 180 270）(输入exit或quit退出程序)：");
                continue;
            }
            result = s;
            break;
        }
        return result;
    }

    /**
     * 获取屏幕锁定方向
     *
     * @param scanner 控制台输入
     * @return 屏幕锁定方向
     */
    private static String getDeviceVideoOrientation(Scanner scanner) {
        //0 自然方向
        //1 逆时针旋转 90
        //2 180°
        //3 顺时针旋转 90
        printMsg("请输入设备显示内容旋转方向（直接输入角度,0~360）(输入exit或quit退出程序)：");
        String result;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入设备显示内容旋转方向（直接输入角度,0~360）(输入exit或quit退出程序)：");
                continue;
            }
            int angle;
            try {
                angle = Integer.parseInt(s);
            } catch (NumberFormatException e) {
                printMsg("请输入正确的设备显示内容旋转方向（直接输入角度,0~360）(输入exit或quit退出程序)：");
                continue;
            }
            if (angle < 0 || angle > 360){
                printMsg("请输入正确的设备显示内容旋转方向（直接输入角度,0~360）(输入exit或quit退出程序)：");
                continue;
            }
            result = s;
            break;
        }
        return result;
    }

    private static void startPrintThread(Process process, InputStream inputStream) {
        new Thread(() -> {
            while (true) {
                if (!process.isAlive()) {
                    break;
                }
                try {
                    int available = inputStream.available();
                    if (available > 0) {
                        byte[] bytes = new byte[available];
                        int read = inputStream.read(bytes);
                        if (read < 0) {
                            break;
                        }
                        String s = new String(bytes, StandardCharsets.UTF_8);
                        printMsg(s);
                    }
                } catch (IOException e) {
                    break;
                }
            }
        }).start();
    }

    private static void printMsg(String msg) {
        System.out.println(msg);
    }

    /**
     * 退出程序
     */
    private static void exit() {
        for (Process process : processes) {
            if (process.isAlive()) {
                process.destroy();
            }
        }
        printMsg("程序已经退出");
        System.exit(0);
    }

    private static int connectDeviceByNetwork(Runtime runtime, Scanner scanner) {
        printMsg("如果您的设备可用网络进行连接，请输入目标设备IP地址(输入exit或quit退出程序)：");
        String ip;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入目标设备IP地址(输入exit或quit退出程序)：");
                continue;
            }
            boolean valid = isIp4Valid(s);
            if (!valid) {
                if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                    return ConstantsCode.EXIT;
                }
                printMsg("请输入正确的IP地址(输入exit或quit退出程序)：");
                continue;
            }
            ip = s;
            break;
        }
        printMsg("正在连接目标设备，请耐心等待...");
        try {
            Process process = runtime.exec(ADB_PATH + " connect " + ip);
            processes.add(process);
            process.waitFor();
            InputStream inputStream = process.getInputStream();
            byte[] bytes = new byte[inputStream.available()];
            int read = inputStream.read(bytes);
            if (read < 0) {
                printMsg("命令执行结果获取失败！");
                return ConstantsCode.ERROR;
            }
            String s = new String(bytes, StandardCharsets.UTF_8);
            printMsg(s);
            PrintWriter writer = new PrintWriter(new StringWriter());
            writer.println();
            if (!s.toLowerCase().startsWith("connected to") && !s.toLowerCase().startsWith("already connected to")) {
                printMsg("与目标设备连接失败！");
                return ConstantsCode.FAIL;
            }
            deviceSerial = ip;
            return ConstantsCode.SUCCESS;
        } catch (IOException | InterruptedException e) {
            printMsg("命令执行失败，请检查运行环境是否正常");
            return ConstantsCode.ERROR;
        }
    }

    /**
     * 列出全部已经连接的设备
     *
     * @param runtime 当前运行环境
     * @param scanner 控制台输入流
     */
    private static int listAndSelectDevices(Runtime runtime, Scanner scanner) {
        try {
            Process process = runtime.exec(ADB_PATH + " devices");
            processes.add(process);
            int waitFor = process.waitFor();
            if (waitFor != 0) {
                printMsg("命令运行失败！");
                return ConstantsCode.ERROR;
            }
            InputStream inputStream = process.getInputStream();
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            String result = new String(bytes);
            result = result.replaceAll("\r", "");
            printMsg(result);
            String[] split = result.split("\n");
            ArrayList<String> devices = clearInvalidLine(split);
            printMsg("计算机上已经连接的设备数量：" + devices.size());
            if (devices.isEmpty()) {
                printMsg("没有已经连接的设备,请连接设备！\n\n");
                return connectDeviceByNetwork(runtime, scanner);
            }
            return selectDevice(runtime, devices, scanner);
        } catch (IOException | InterruptedException e) {
            printMsg("找不到adb.exe，请确认adb已经安装到系统环境变量中！");
            return ConstantsCode.ERROR;
        }
    }

    private static ArrayList<String> clearInvalidLine(String[] split) {
        ArrayList<String> devices = new ArrayList<>();
        for (String s : split) {
            String cache = s.trim();
            if (cache.isEmpty()) {
                continue;
            }
            if (cache.equalsIgnoreCase("List of devices attached")) {
                continue;
            }
            devices.add(cache);
        }
        return devices;
    }

    private static int selectDevice(Runtime runtime, ArrayList<String> devices, Scanner scanner) {
        printMsg("已经连接的设备如下：");
        for (int i = 0; i < devices.size(); i++) {
            printMsg((i + 1) + ": " + devices.get(i));
        }
        printMsg("请输入要连接的设备序号(输入exit或quit退出程序,输入network连接一个新的设备)：");
        int index;
        while (true) {
            boolean nextLine = scanner.hasNextLine();
            if (!nextLine) {
                continue;
            }
            String s = scanner.nextLine().trim();
            if (s.isEmpty()) {
                printMsg("请输入要连接的设备序号(输入exit或quit退出程序,输入network连接一个新的设备)：");
                continue;
            }

            if (s.equalsIgnoreCase("exit") || s.equalsIgnoreCase("quit")) {
                return ConstantsCode.EXIT;
            } else if (s.equalsIgnoreCase("network")) {
                return connectDeviceByNetwork(runtime, scanner);
            }

            try {
                int indexFromInput = Integer.parseInt(s);
                int realIndex = indexFromInput - 1;
                if (realIndex < 0 || realIndex > devices.size() - 1) {
                    printMsg("请输入正确的序号(输入exit或quit退出程序,输入network连接一个新的设备)：");
                    continue;
                }
                index = realIndex;
            } catch (NumberFormatException e) {
                printMsg("请输入正确的序号(输入exit或quit退出程序)：");
                continue;
            }
            break;
        }
        String s = devices.get(index);
        String deviceSerial = s.split("\t")[0];
        String deviceName = s.split("\t")[1];
        if (deviceName.isEmpty()) {
            deviceName = deviceSerial;
        }
        printMsg("选择的目标设备序列号（或IP地址）：" + deviceSerial + "设备名称：" + deviceName);
        if (deviceName.equalsIgnoreCase("offline")) {
            printMsg("设备不在线，请断开后重连该设备，或尝试重启该设备！");
            return ConstantsCode.FAIL;
        }
        MultipleRemoteControlMain.deviceSerial = deviceSerial;
        return ConstantsCode.SUCCESS;
    }

    /**
     * 判断IPV4地址是否合法
     *
     * @param ip IPV4地址
     * @return true：合法；false：不合法
     */
    private static boolean isIp4Valid(String ip) {
        String[] split = ip.split(":");
        if (split.length == 1) {
            return ip.matches(IP_V4_ADDRESS_REGEX);
        } else if (split.length == 2) {
            return split[0].matches(IP_V4_ADDRESS_REGEX) && isValidPort(split[1]);
        } else {
            return false;
        }
    }

    /**
     * 判断端口号是否合法
     * @param portString 端口号字符串
     * @return true：合法；false：不合法
     */
    private static boolean isValidPort(String portString) {
        try {
            int port = Integer.parseInt(portString);
            return port >= 0 && port <= 65535;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
